﻿using CDV.IRMS.Model;
using CDV.IRMS.WebAPI.TaskExecution.Data;
using CDV.IRMS.WebAPI.TaskExecution.Utils;
using log4net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;

namespace CDV.IRMS.WebAPI.TaskExecution.Filter
{
    /// <summary>
    /// 校验入参过滤器
    /// </summary>
    public class ValidateModelAttribute : ActionFilterAttribute
    {
        /// <summary>
        /// Log对象
        /// </summary>
        private readonly ILog _logger = ServiceInjector.ServiceProvider.GetService<ILog>();

        /// <summary>
        /// Action的功能描述
        /// </summary>
        private readonly string _actionDescription;

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="actionDescription">Action的功能描述</param>
        public ValidateModelAttribute(string actionDescription)
        {
            _actionDescription = actionDescription;
        }

        /// <summary>
        /// 校验入参
        /// </summary>
        /// <param name="context">ActionExecutingContext</param>
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            var errorMsg = string.Empty;
            try
            {
                //Action执行前Debug信息
                var inputParameter = JsonConvert.SerializeObject(context.ActionArguments);
                _logger.Debug($"▼***{_actionDescription}***▼，入参：[{inputParameter}]");

                var action = context.ActionDescriptor as ControllerActionDescriptor;
                switch (action.ActionName)
                {
                    //获取路由列表
                    case ActionName.LIST:
                        //开始时间
                        if (!context.ActionArguments.ContainsKey("beginTime")
                            || !DateTime.TryParse(context.ActionArguments["beginTime"].ToString(), out DateTime dtBeginTime)
                            || dtBeginTime == DateTime.MinValue)
                        {
                            errorMsg = "开始时间为空或者不是一个有效的时间";
                            context.Result = new JsonResult(new { RouteList = new List<TaskRouteInfoModel>(), ErrorMsg = errorMsg });
                            return;
                        }

                        //结束时间
                        if (!context.ActionArguments.ContainsKey("endTime")
                            || !DateTime.TryParse(context.ActionArguments["endTime"].ToString(), out DateTime dtEndTime)
                            || dtEndTime == DateTime.MinValue)
                        {
                            errorMsg = "结束时间为空或者不是一个有效的时间";
                            context.Result = new JsonResult(new { RouteList = new List<TaskRouteInfoModel>(), ErrorMsg = errorMsg });
                            return;
                        }

                        //时间范围的有效性校验
                        if (dtBeginTime > dtEndTime)
                        {
                            errorMsg = $"开始时间[{dtBeginTime}]不能大于结束时间[{dtEndTime}";
                            context.Result = new JsonResult(new { RouteList = new List<TaskRouteInfoModel>(), ErrorMsg = errorMsg });
                            return;
                        }

                        //路由状态参数校验
                        if (context.ActionArguments.ContainsKey("routeStatus")
                            && context.ActionArguments["routeStatus"] != null
                            && int.TryParse(context.ActionArguments["routeStatus"].ToString(), out int routeStatus)
                            && (routeStatus < (int)ERouteStatus.None || routeStatus > (int)ERouteStatus.Finish))
                        {
                            errorMsg = $"路由线路状态值[{context.ActionArguments["routeStatus"]}]无效";
                            context.Result = new JsonResult(new { RouteList = new List<TaskRouteInfoModel>(), ErrorMsg = errorMsg });
                            return;
                        }
                        break;
                    //执行
                    case ActionName.EXECUTE:
                    //应急切
                    case ActionName.TAKE:
                        var parameter = context.ActionArguments["parameter"] as ExecuteParameter;
                        if (parameter == null)
                        {
                            return;
                        }
                        //任务ID
                        if (parameter.TaskID <= 0)
                        {
                            errorMsg = $"任务ID[{parameter.TaskID}]无效";
                            context.Result = new JsonResult(new { parameter.TaskID, parameter.RouteID, ErrorMsg = errorMsg });
                            return;
                        }

                        //路由ID
                        if (parameter.RouteID <= 0)
                        {
                            errorMsg = $"路由ID[{parameter.RouteID}]无效";
                            context.Result = new JsonResult(new { parameter.TaskID, parameter.RouteID, ErrorMsg = errorMsg });
                            return;
                        }

                        //源节点ID
                        if (string.IsNullOrEmpty(parameter.SrcNodeID))
                        {
                            errorMsg = $"源节点ID[{parameter.SrcNodeID}]为空";
                            context.Result = new JsonResult(new { parameter.TaskID, parameter.RouteID, ErrorMsg = errorMsg });
                            return;
                        }

                        //目的节点ID
                        if (string.IsNullOrEmpty(parameter.DestNodeID))
                        {
                            errorMsg = $"目的节点ID[{parameter.DestNodeID}]为空";
                            context.Result = new JsonResult(new { parameter.TaskID, parameter.RouteID, ErrorMsg = errorMsg });
                            return;
                        }
                        break;
                    //结束路由执行
                    case ActionName.FINISH:
                    //路由复位
                    case ActionName.RESET:
                        //任务ID
                        bool hasTaskID = context.ActionArguments.TryGetValue("taskID", out object objTaskID);
                        //路由ID
                        bool hasRouteID = context.ActionArguments.TryGetValue("routeID", out object objRouteID);
                        //任务ID无效
                        if (hasTaskID && IsInValid(objTaskID, out int taskID))
                        {
                            errorMsg = $"任务ID[{objTaskID}]无效";
                            context.Result = new JsonResult(new { TaskID = objTaskID, RouteID = objRouteID, ErrorMsg = errorMsg });
                            return;
                        }

                        //路由ID无效
                        if (hasRouteID && IsInValid(objRouteID, out int routeID))
                        {
                            errorMsg = $"路由ID[{objRouteID}]无效";
                            context.Result = new JsonResult(new { TaskID = objTaskID, RouteID = objRouteID, ErrorMsg = errorMsg });
                            return;
                        }
                        break;
                    default:
                        base.OnActionExecuting(context);
                        return;
                }
            }
            catch (Exception ex)
            {
                _logger.Error($"▲***{_actionDescription}***▲，校验入参失败，异常信息如下：[{ex}]");
                context.Result = new JsonResult(new { TaskID = -1, RouteID = -1, ErrorMsg = $"校验入参失败，异常信息如下：[{ex.Message}]" });
            }
            finally
            {
                if (!string.IsNullOrEmpty(errorMsg))
                {
                    _logger.Warn($"▲***{_actionDescription}***▲，执行结果：失败[原因：{errorMsg}]");
                }
            }
        }

        /// <summary>
        /// Action执行结束
        /// </summary>
        /// <param name="context">ActionExecutedContext</param>
        public override void OnActionExecuted(ActionExecutedContext context)
        {
            try
            {
                var action = context.ActionDescriptor as ControllerActionDescriptor;

                //Action发生异常
                if (context.Exception != null)
                {
                    ////路由参数
                    ////var routeParameter = GetRouteParameter(context);
                    ////_logger.Error($"▲***{_actionDescription}***▲，入参：[{routeParameter}]，执行结果：[失败，异常信息如下：{errorMsg}]");

                    var exceptionMsg = GetRealExceptionMessage(context.Exception);
                    _logger.Error($"▲***{_actionDescription}***▲，执行结果：失败[异常信息如下：{exceptionMsg}]");
                    context.ExceptionHandled = true;
                    switch (action.ActionName)
                    {
                        //获取路由列表
                        case ActionName.LIST:
                            context.Result = new JsonResult(new { RouteList = new List<TaskRouteInfoModel>(), ErrorMsg = $"[{_actionDescription}]执行失败，异常信息如下：{exceptionMsg }" });
                            break;
                        //执行
                        case ActionName.EXECUTE:
                        //应急切
                        case ActionName.TAKE:
                        //结束路由执行
                        case ActionName.FINISH:
                        //路由复位
                        case ActionName.RESET:
                            context.Result = new JsonResult(new { TaskID = 0, RouteID = 0, ErrorMsg = $"[{_actionDescription}]执行失败，异常信息如下：{exceptionMsg }" });
                            break;
                        default:
                            base.OnActionExecuted(context);
                            break;
                    }
                    return;
                }

                var jsonResult = context.Result as JsonResult;
                if (jsonResult == null || jsonResult.Value == null)
                {
                    base.OnActionExecuted(context);
                    return;
                }

                //解析Action返回值
                var result = JsonConvert.SerializeObject(jsonResult.Value);
                var errorMsg = string.Empty;
                //获取路由列表
                if (action.ActionName == ActionName.LIST)
                {
                    var tempResult = JsonConvert.DeserializeAnonymousType(result, new { RouteList = new List<TaskRouteInfoModel>(), ErrorMsg = string.Empty });
                    errorMsg = tempResult.ErrorMsg;
                }
                else
                {
                    var tempResult = JsonConvert.DeserializeAnonymousType(result, new { TaskID = 0, RouteID = 0, ErrorMsg = string.Empty });
                    errorMsg = tempResult.ErrorMsg;
                }

                //有错误信息
                if (!string.IsNullOrEmpty(errorMsg))
                {
                    _logger.Warn($"▲***{_actionDescription}***▲，执行结果：失败[原因：{errorMsg}]");
                }
                else
                {
                    _logger.Debug($"▲***{_actionDescription}***▲，执行结果：[{result}]");
                }
            }
            catch (Exception ex)
            {
                _logger.Error($"▲***{_actionDescription}***▲，未知异常，信息如下：[{ex}]");
            }
        }

        /// <summary>
        /// 获取路由参数
        /// </summary>
        /// <param name="context">ActionExecutedContext</param>
        /// <returns>路由参数</returns>
        private static string GetRouteParameter(ActionExecutedContext context)
        {
            if (context.RouteData.Values == null || context.RouteData.Values.Count <= 2)
            {
                return string.Empty;
            }

            var routeParameter = string.Empty;
            foreach (var parameter in context.RouteData.Values)
            {
                if (parameter.Key == "action" || parameter.Key == "controller")
                {
                    continue;
                }
                routeParameter += $"{parameter.Key}={parameter.Value},";
            }

            return routeParameter.Substring(0, routeParameter.Length - 1);
        }

        /// <summary>
        /// 获取异常信息
        /// </summary>
        /// <param name="ex">异常</param>
        /// <returns>异常信息</returns>
        private static string GetRealExceptionMessage(Exception ex)
        {
            var errorMsg = ex.Message;
            var innerException = ex.InnerException;
            while (innerException != null)
            {
                errorMsg += "--->" + innerException.Message;
                innerException = innerException.InnerException;
            }

            return errorMsg;
        }

        /// <summary>
        /// 判断value是否有效（>0）
        /// </summary>
        /// <param name="value">入参</param>
        /// <param name="id">转换后的返回值</param>
        /// <returns>true：入参无效</returns>
        private static bool IsInValid(object value, out int id)
        {
            id = 0;
            if (value == null
                || !int.TryParse(value.ToString(), out int tempID))
            {
                return true;
            }

            if (tempID <= 0)
            {
                return true;
            }

            id = tempID;
            return false;
        }
    }
}
